package productStatsTests;

import static org.junit.Assert.*;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import org.junit.Before;
import org.junit.Test;

import coreModel.Unit;

import reports.builders.TestBuilder;

public class JTestRunner
{
	DataGen gen;
	
	@Before
	public void init()
	{
		gen = new DataGen();
	}
	
	////////////////////The individual test methods, one per test case
	@Test
	//generate product with description "d"
	public void shortDesc()
	{
		descTest("d");
	}

	@Test
	//generate product with description "description d " repeated
	public void longDescSpaces()
	{
		descTest(" description d description d description d" + 
				" description d description d description d description d");
	}

	@Test
	//generate product with description "descriptionD" repeated (no spaces)
	public void longDescNoSpaces()
	{
		descTest("descriptionDdescriptionDdescriptionDdescriptionD" + 
				"descriptionDdescriptionDdescriptionDdescriptionDdescriptionD");
	}
	
	@Test
	//generate two products with descriptions that have different first letters,
	// adding them in reverse alphabetical order
	public void firstLetterDiffDesc()
	{
		descTest("hat description", "cat description");
	}
	
	@Test
	//generate two products with descriptions that have one letter different,
	// adding them in reverse alphabetical order
	public void oneLetterDiffDesc()
	{
		descTest("description hat", "description cat");
	}
	
	@Test
	//generate two products with the same description
	public void sameDesc()
	{
		descTest("description cat", "description cat");
	}
	
	@Test
	//generate a product with a random description of random length
	public void normalDesc()
	{
		normalProdTest();
	}
	
	
	
	@Test
	//generate a product with a three month supply of 0
	public void zeroMonthSupply()
	{
		threeMonthSupplyTest(0);
	}

	@Test
	//generate a product with a three month supply of 1
	public void oneMonthSupply()
	{
		threeMonthSupplyTest(1);
	}
	
	@Test
	//generate a product with a random three month supply
	public void averageMonthSupply()
	{
		normalProdTest();
	}
	


	@Test
	//generate a product with a barcode of a single character
	public void shortBarcode()
	{
		barcodeTest("3");
	}

	@Test
	//generate a product with a long barcode
	public void longBarcode()
	{
		barcodeTest("01234567890123456789012345678901234567890123456789012345678901234567890");
	}

	@Test
	//generate a product with a barcode of all zeros
	public void zerosBarcode()
	{
		barcodeTest("0000000000000000");
	}
	
	@Test
	//generate a product with a random barcode
	public void averageBarcode()
	{
		normalProdTest();
	}
	
	

	@Test
	//generate a product with a size of type "count"
	public void countSize()
	{
		sizeTest(1, Unit.COUNT);
	}

	@Test
	//generate a product with a size of type "fluid ounces"
	public void fluidOuncesSize()
	{
		sizeTest(3, Unit.FLUID_OUNCES);
	}

	@Test
	//generate a product with a decimal size
	public void decimalSize()
	{
		sizeTest(5.5F, Unit.GALLONS);
	}

	@Test
	//generate a product with an average size
	public void averageSize()
	{
		normalProdTest();
	}
	
	
	
	
	@Test
	//generate a product with items all added before the reporting period and never removed
	public void outsideReportingPeriod()
	{
		//dates before period began, and never removed
		Calendar date1 = new GregorianCalendar(2010,0,3);
		Calendar date2 = new GregorianCalendar(2010,5,3);
		Calendar date3 = new GregorianCalendar(2011,0,3);
		itemDatesTest(date1.getTime(), date2.getTime(), date3.getTime());
	}
	
	@Test
	//generate an item removed the day it was added (before reporting period)
	public void itemGone1()
	{
		//pick one date: March 3, 2011
		Calendar date1 = new GregorianCalendar(2011,2,3);
		itemDatesTest(date1.getTime(), date1.getTime());
	}
	
	@Test
	//generate an item removed the day it was added (during reporting period)
	public void itemGone2()
	{
		//pick one date: March 3, 2012
		Calendar date1 = new GregorianCalendar(2012,2,3);
		itemDatesTest(date1.getTime(), date1.getTime());
	}
	
	@Test
	//generate three items added today
	public void itemsToday()
	{
		itemDatesTest(new Date(), new Date(), new Date());
	}
	
	
	////////////////////Several varieties of general tests

	public void descTest(String d)
	{
		gen.setDescription(d);

		//check against correct output
		assertTrue(testAgainstExpected());
	}

	public void descTest(String d1, String d2)
	{
		gen.setDescription(d1);
		gen.addProduct();
		gen.setDescription(d2);

		//check against correct output
		assertTrue(testAgainstExpected());
	}
	
	private void threeMonthSupplyTest(int i) 
	{
		gen.setThreeMonthSupply(i);
		
		//check against correct output
		assertTrue(testAgainstExpected());
	}

	private void barcodeTest(String b) 
	{
		gen.setBarcode(b);
		
		//check against correct output
		assertTrue(testAgainstExpected());
	}

	public void normalProdTest()
	{
		gen.addProduct();
		gen.addProduct();

		//check against correct output
		assertTrue(testAgainstExpected());
	}

	private void sizeTest(float s, Unit u) 
	{
		gen.setSize(s);
		gen.setUnit(u);

		//check against correct output
		assertTrue(testAgainstExpected());
	}
	
	public void itemDatesTest(Date d1, Date d2)
	{
		gen.setEntryDate(d1);
		gen.setCreationDate(d2);
		gen.setExitTime(d2);

		//check against correct output
		assertTrue(testAgainstExpected());
	}
	
	public void itemDatesTest(Date d1a, Date d2a, Date d1b, Date d2b, Date d1c, Date d2c)
	{
		gen.setCreationDate(d2a);
		gen.setEntryDate(d1a);
		gen.setExitTime(d2a);
		
		gen.addItem();
		gen.setEntryDate(d1b);
		gen.setExitTime(d2b);

		gen.addItem();
		gen.setEntryDate(d1c);
		gen.setExitTime(d2c);

		//check against correct output
		assertTrue(testAgainstExpected());
	}
	
	public void itemDatesTest(Date d1, Date d2, Date d3)
	{
		gen.setEntryDate(d1);
		
		gen.addItem();
		gen.setEntryDate(d2);

		gen.addItem();
		gen.setEntryDate(d3);

		//check against correct output
		assertTrue(testAgainstExpected());
	}
	
	public void ageTest(Date d1, Date d2)
	{
		gen.addItem();
		gen.setEntryDate(d1);
		gen.setCreationDate(d2);
		gen.setExitTime(d2);

		//check against correct output
		assertTrue(testAgainstExpected());
	}
	
	
	/////////////////////Helper functions

	public boolean testAgainstExpected()
	{
		//determine correct output
		TestBuilder expected = gen.getExpected();
		
		//get actual output
		TestBuilder actual = gen.getActual();
		
		return compareTestBuilders(expected, actual);
	}

	private boolean compareTestBuilders(TestBuilder expected, TestBuilder actual) 
	{
		if (expected.getRowCount() != actual.getRowCount())
		{
			System.out.println("length " + expected.getRowCount() 
					+ " doesn't match length " + actual.getRowCount());
			return false;
		}

		//compare all strings of each row 
		String[] rowE = new String[0];
		String[] rowA = new String[0];
		for (int i=0; i<expected.getRowCount(); i++)
		{
			rowE = expected.getRow(i).toArray(rowE);
			rowA = actual.getRow(i).toArray(rowA);
			for (int j=0; j<rowE.length; j++)
				if (rowE[j].compareTo(rowA[j]) != 0)
				{
					System.out.println("\"" + rowE[j] + "\" doesn't match \"" + rowA[j] + "\"");
					return false;
				}
		}
		
		return true;
	}
}